package com.zksite.nator.client.processor;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.zksite.nator.client.config.MappingConfig;
import com.zksite.nator.client.server.handler.ConnectionWatchdog;
import com.zksite.nator.common.config.Config;
import com.zksite.nator.common.constants.Constants;
import com.zksite.nator.common.constants.ErrorCode;
import com.zksite.nator.common.model.ResponseModel;
import com.zksite.nator.common.processor.RequestProcessor;
import com.zksite.nator.common.util.Reflections;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.ReferenceCountUtil;

@Component
public class InternalRequestProcessor implements RequestProcessor {

    @Autowired
    private MappingConfig mappingConfig;

    private static final Logger LOGGER = LoggerFactory.getLogger(InternalRequestProcessor.class);

    private static final String PONG = "pong";

    public boolean process(ChannelHandlerContext ctx, Object msg) {
        HttpRequest httpRequest = (HttpRequest) msg;
        String messageType = httpRequest.headers().get(Constants.MESSAGE_TYPE);
        Method method = Reflections.getAccessibleMethodByName(this, messageType);
        if (method == null) {
            return false;
        }
        try {
            method.invoke(this, ctx, msg);
            return true;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return false;
    }

    public void requestMapping(ChannelHandlerContext ctx, Object msg) {
        Config config = mappingConfig.getConfig();
        ByteBuf byteBuf;
        if (config == null) {
            ResponseModel responseModel =
                    new ResponseModel(ErrorCode.BIZ_EXCEPTION.getErrcode(), "配置文件为空", null);
            byteBuf = Unpooled.wrappedBuffer(JSONObject.toJSONString(responseModel).getBytes());
        } else {
            byteBuf = Unpooled.wrappedBuffer(JSONObject.toJSONString(config).getBytes());
        }
        DefaultFullHttpResponse response =
                new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
        response.headers().add(Constants.MESSAGE_TYPE, Constants.MESSAGE_RESPONSE_MAPPING);
        response.headers().add("Content-Length", byteBuf.array().length);
        ctx.writeAndFlush(response);
        LOGGER.info("send response mapping config");
        ReferenceCountUtil.release(msg);
    }

    public void ping(ChannelHandlerContext ctx, Object msg) {
        ByteBuf byteBuf;
        byteBuf = Unpooled.wrappedBuffer(PONG.getBytes());
        HttpResponse response =
                new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
        response.headers().add(Constants.MESSAGE_TYPE, Constants.MESSAGE_PONG);
        response.headers().add("Content-Length", byteBuf.array().length);
        ctx.writeAndFlush(response);
        ReferenceCountUtil.release(msg);
        LOGGER.debug("Reply PONG message");
    }

    public void info(ChannelHandlerContext ctx, Object msg) {
        FullHttpRequest request = (FullHttpRequest) msg;
        byte[] body = new byte[request.content().readableBytes()];
        request.content().getBytes(0, body);
        try {
            String json = new String(body, "utf-8");
            ResponseModel model = JSONObject.parseObject(json, ResponseModel.class);
            if (!model.getRet().equals(ErrorCode.NORMAL.getErrcode())) {
                LOGGER.error(model.getMsg());
                ConnectionWatchdog connectionWatchdog =
                        ctx.pipeline().get(ConnectionWatchdog.class);
                ctx.pipeline().remove(connectionWatchdog);
                ctx.close();
            } else {
                LOGGER.info(model.getMsg());
            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

}
